local PermissionBlock = {}
PermissionBlock.__index = PermissionBlock

Tubes.PermissionBlock = Tubes.MakeConstructor (PermissionBlock)

--[[
	Events
	
	InheritFromParentChanged (PermissionBlock block)
]]

function PermissionBlock:ctor (getParentBlock)
	self.Name = ""
	self.Owner = nil
	self.OwnerName = "Server"
	self.OwnerSteamID = ""
	self.Template = nil
	self.Groups = {}
	self.PermissionList = nil
	self.InheritFromParent = true
	
	self.EventProvider = Tubes.EventProvider (self)
	self.GetParentBlock = getParentBlock
end

function PermissionBlock:AddGroupPermission (group, permission)
	if type (group) == "string" then
		group = Tubes.Permissions.GetGroup (group)
	end
	self.Groups [group] = self.Groups [group] or {}
	self.Groups [group] [permission] = true
end

function PermissionBlock:ClearGroupPermission (group, permission)
	if type (group) == "string" then
		group = Tubes.Permissions.GetGroup (group)
	end
	if not self.Groups [group] then
		return
	end
	self.Groups [group] [permission] = nil
end

function PermissionBlock:GetGroupPermission (group, permission)
	if type (group) == "string" then
		group = Tubes.Permissions.GetGroup (group)
	end
	if self.Groups [group] and
		self.Groups [group] [permission] ~= nil then
		return self.Groups [group] [permission]
	end
	if not self.InheritFromParent then
		return nil
	end
	local ParentBlock = self.GetParentBlock and self:GetParentBlock ()
	return ParentBlock and ParentBlock:GetGroupPermission (group, permission)
end

function PermissionBlock:GetGroups ()
	return self.Groups
end

function PermissionBlock:GetInheritFromParent ()
	return self.InheritFromParent
end

function PermissionBlock:GetOwner ()
	return self.Owner, self.OwnerName, self.OwnerSteamID
end

function PermissionBlock:GetOwnerName ()
	return self.Owner and self.Owner:IsValid () and self.Owner:Name () or self.OwnerName
end

function PermissionBlock:GetName ()
	return self.Name or ""
end

function PermissionBlock:GetParentPermissions ()
	if not self.GetParentBlock then
		return nil
	end
	return self:GetParentBlock ()
end

local EmptyPermissions = {}
function PermissionBlock:GetPermissionList ()
	return self.PermissionList or EmptyPermissions
end

function PermissionBlock:GetPlayerPermission (ply, permission)
	local PermissionBlock = self
	local Allow = false
	while PermissionBlock do
		for Group, Permissions in pairs (PermissionBlock:GetGroups ()) do
			if Group:IsInGroup (self, ply) then
				if Permissions [permission] == false then
					return false
				end
				Allow = Allow or Permissions [permission]
			end
		end
		if PermissionBlock.InheritFromParent then
			PermissionBlock = PermissionBlock.GetParentBlock and PermissionBlock:GetParentBlock ()
		else
			PermissionBlock = nil
		end
	end
	return Allow
end

function PermissionBlock:IsEmpty ()
	return not next (self.Groups)
end

function PermissionBlock:Receive (netMessage)
	local OwnerID = netMessage:UChar ()
	if OwnerID == 255 then
		self:SetOwner (nil, "Server")
	else
		self:SetOwner (ents.GetByIndex (OwnerID))
	end
	self:SetInheritFromParent (netMessage:UChar () == 1 and true or false)
	local GroupIndex = netMessage:UShort ()
	while GroupIndex ~= 0 do
		local Group = Tubes.Permissions.GetGroup (Tubes.Permissions.StringPool:LookupString (GroupIndex))
		self.Groups [Group] = self.Groups [Group] or {}
		local Permissions = self.Groups [Group]
		local Allow = netMessage:String ()
		while Allow ~= "" do
			Permissions [Allow] = true
			Allow = netMessage:String ()
		end
		local Deny = netMessage:String ()
		while Deny ~= "" do
			Permissions [Deny] = true
			Deny = netMessage:String ()
		end
		GroupIndex = netMessage:UShort ()
	end
end

function PermissionBlock:RemoveGroupPermission (group, permission)
	if type (group) == "string" then
		group = Tubes.Permissions.GetGroup (group)
	end
	if not self.Groups [group] then
		return
	end
	self.Groups [group] [permission] = false
end

function PermissionBlock:Send (netMessage)
	if self.Owner then
		netMessage:UChar (self.Owner:EntIndex ())
	else
		netMessage:UChar (255)
	end
	netMessage:UChar (self:GetInheritFromParent () and 1 or 0)
	for Group, Permissions in pairs (self.Groups) do
		local Index = Tubes.Permissions.StringPool:LookupStringIndex (Group:GetFullName (), true)
		netMessage:UShort (Index)
		for Permission, Value in pairs (Permissions) do
			if Value then
				netMessage:String (Permission)
			end
		end
		netMessage:String ("")
		for Permission, Value in pairs (Permissions) do
			if not Value then
				netMessage:String (Permission)
			end
		end
		netMessage:String ("")
	end
	netMessage:UShort (0)
end

function PermissionBlock:SetInheritFromParent (inheritFromParent)
	if self.InheritFromParent == inheritFromParent then
		return
	end
	self.InheritFromParent = inheritFromParent
	self:DispatchEvent ("InheritFromParentChanged", self)
end

function PermissionBlock:SetName (name)
	self.Name = name
end

function PermissionBlock:SetOwner (owner, ownerName, ownerSteamID)
	if type (owner) == "Player" then
		ownerName = ownerName or owner:Name ()
		ownerSteamID = ownerSteamID or Tubes.GetPlayerSteamID (owner)
	end
	
	self.Owner = owner
	self.OwnerName = ownerName
	self.OwnerSteamID = ownerSteamID or ""
end

function PermissionBlock:SetPermissionList (permissionList)
	self.PermissionList = permissionList
end